package com.xjrsoft.module.fabric;

import lombok.Data;
import org.apache.commons.lang3.RandomStringUtils;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.gateway.impl.GatewayImpl;
import org.hyperledger.fabric.sdk.Peer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.EnumSet;

/**
 * @author wwn
 * @date 2024年12月10日 17:10
 */
@Configuration
@Data
public class FabricConfig {
    /**
     * wallet文件夹路径
     */
    @Value("${fabric.walletDirectory}")
    private String walletDirectory;
    /**
     * 网络配置文件路径
     */
    @Value("${fabric.networkConfigPath}")
    private String networkConfigPath;
    /**
     * 用户证书路径
     */
    @Value("${fabric.org1.certificatePath}")
    private String certificatePath;
    @Value("${fabric.org2.certificatePath}")
    private String certificatePathOrgTwo;
    /**
     * 用户私钥路径
     */
    @Value("${fabric.org1.privateKeyPath}")
    private String privateKeyPath;
    @Value("${fabric.org2.privateKeyPath}")
    private String privateKeyPathOrgTwo;
    /**
     * 访问的组织名
     */
    @Value("${fabric.org1.mspid}")
    private String mspid;
    @Value("${fabric.org2.mspid}")
    private String mspidOrgTwo;
    /**
     * 用户名
     */
    @Value("${fabric.username}")
    private String username;
    /**
     * 通道名字
     */
    @Value("${fabric.channelName}")
    private String channelName;
    /**
     * 链码名字
     */
    @Value("${fabric.contractName}")
    private String contractName;

    public Network getNetwork(String org) {
        X509Certificate certificate = null;
        PrivateKey privateKey = null;
        Gateway gateway = null;
        Network network = null;
        try {
            Wallet wallet = Wallets.newInMemoryWallet();
            String certificatePathStr = this.certificatePath;
            String privateKeyPathStr = this.privateKeyPath;
            String mspid = this.mspid;
            if (org.equals("org2")) {
                certificatePathStr = this.certificatePathOrgTwo;
                privateKeyPathStr = this.privateKeyPathOrgTwo;
                mspid = this.mspidOrgTwo;
            }
            Path certificatePath = Paths.get(certificatePathStr);
            certificate = readX509Certificate(certificatePath);

            Path privateKeyPath = Paths.get(privateKeyPathStr);
            privateKey = getPrivateKey(privateKeyPath);

            wallet.put(username, Identities.newX509Identity(mspid, certificate, privateKey));

            //根据connection-org1.json 获取Fabric网络连接对象
            GatewayImpl.Builder builder = (GatewayImpl.Builder) Gateway.createBuilder();

            builder.identity(wallet, this.username).networkConfig(Paths.get(this.networkConfigPath));
            //连接网关
            gateway = builder.connect();
            //获取mychannel通道
            network = gateway.getNetwork(this.channelName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return network;
    }

    public Contract getContract(Network network) {
        Contract contract = null;
        try {
            contract = network.getContract(this.contractName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contract;
    }

    private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
        try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
            return Identities.readX509Certificate(certificateReader);
        }
    }

    private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
        try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
            return Identities.readPrivateKey(privateKeyReader);
        }
    }

    public String cohain(String org, String method, String key, String body) {
        String hash = "";
        try {
            Network network = this.getNetwork(org);
            String param = "";
            switch (method) {
                case "add":
                case "register":
                    param = "create";
                    break;
                case "edit":
                    param = "update";
                    break;
                case "delete":
                    param = "delete";
                    break;
            }
            byte[] invokeResult =  this.getContract(network).createTransaction(param)
                    .setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
                    .submit( key, body);
            hash = new String(invokeResult, StandardCharsets.UTF_8);
        } catch (Exception e) {
            hash = RandomStringUtils.random(64, "0123456789abcdefghijklmnopqrstuvwxyz");
            e.printStackTrace();
        }
        return hash;
    }
}
